/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Communication;

import Accelerometer.WrongWASADataFormatException;
import Accelerometer.AccStreamMeasurement;
import Accelerometer.Accelerometer;
import Wasa.Acceleration;
import Wasa.Response;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Time;
import java.util.ArrayList;
import java.util.StringTokenizer;

/**
 *
 * @author gianmariospacagna
 */
public class Communicator {

    private CommInterface myATCommand;
    private AccStreamMeasurement myASM;
    private String incompleteToken;
    private int accSeqId;
    private int num;
    private ArrayList<Acceleration> accMeasures;

    public Communicator(String port) {
        this.myATCommand = new CommInterface(port);
        this.incompleteToken = null;
        this.accSeqId = 0;
        this.num = 0;


        accMeasures = new ArrayList<Acceleration>();

    }

    private Response generateResponse(String responseStr) {
        int k = responseStr.indexOf("\n");
        if (k > 0) {
            responseStr = responseStr.substring(0, k - 1);
        }
        try {
            //System.out.println("String received: " + responseStr);
            float value = Float.parseFloat(responseStr);
            //System.out.println("Value of value: " + value);
            return new Response(responseStr);



        } catch (NumberFormatException e) {
            //System.out.println(e);

            //System.out.println("!!!Invalid data value!!!");

            if (responseStr.startsWith("OK")) {
                return new Response("OK");
            } else {
                return new Response("ERROR");
            }
        }
    }

    public Response measureTemp() {
        String responseStr = myATCommand.sendATCommand("ATS204?");

        return generateResponse(responseStr);

    }

    public Response ok() {
        String responseStr = myATCommand.sendATCommand("AT");

        return generateResponse(responseStr);
    }

    public Response measureAx() {
        String responseStr = myATCommand.sendATCommand("ATS2021?");
        return generateResponse(responseStr);

    }

    public Response measureLight() {
        String responseStr = myATCommand.sendATCommand("ATS203?");
        return generateResponse(responseStr);
    }

    public Acceleration measureAcceleration() throws WrongWASADataFormatException {

        String responseStr = myATCommand.sendATCommand("AT+OAW?");
        //System.out.println("Response:\n" + responseStr);

        return generateAccelerationMeasure(-1, responseStr);
    }

    /**
     * Parse the string and extract x y z acceleration values
     * @param responseStr
     * @return the acceleration object related
     */
    public void startAccStream(AccStreamMeasurement asm, int rate) {
        this.myASM = asm;
        myATCommand.startAccStream(this, rate);
    }

    public void newDataAvailable(byte[] data) throws WrongWASADataFormatException {
        //System.out.println("Communicator: Data received"+num++);
        String s = new String(data);
        System.out.println("Communicator: data received " + s);
        accMeasures.clear();


        String accStr = "";
        if (incompleteToken != null) {
            accStr = incompleteToken;
        }
        int k = -2;
        while (k != -1) {
            k = s.indexOf("\n");
            if (k == -1) {
                accStr += s;
            } else {
                s = s.substring(k);
                accStr += s;
            }

            int validity = checkValidity(accStr);
            if (validity == 1) {
                //System.out.println("Valid Token: " + accStr);
                Acceleration a = generateAccelerationMeasure(accSeqId++, accStr);

                this.accMeasures.add(a);
                //System.out.println("Communicator: acc " + a.toString());

                incompleteToken = null;

            } else if (validity == 0) {
                //System.out.println("Incomplete token: " + accStr);
                incompleteToken = accStr;
            } else if (validity == -1) {
                //System.out.println("Not valid token: " + accStr);
                incompleteToken = null;
            }
        }






        System.out.println("Communicator: i am sending new data: ");
        for (Acceleration x : accMeasures) {
            System.out.println(x.toString());
        }
        myASM.newDataAvailable(accMeasures);

    }

    public Acceleration generateAccelerationMeasure(long seqId, String responseStr) throws WrongWASADataFormatException{

        
        String msrStr="";
        if (responseStr.startsWith("DATA AXL")) {
            msrStr = responseStr.substring(10);

        } else if (responseStr.startsWith("+OAW")) {
            msrStr = responseStr.substring(6);

        } else {
            throw new WrongWASADataFormatException();
            
            
        }
        StringTokenizer tokenizer = new StringTokenizer(msrStr);
        double x = Float.parseFloat(tokenizer.nextToken(","));
        double y = Float.parseFloat(tokenizer.nextToken(","));
        double z = Float.parseFloat(tokenizer.nextToken("\n").substring(1));
        if (seqId == -1) {
            seqId = System.currentTimeMillis();
        }
        return new Acceleration(seqId, x, y, z);

    }

    /**
     * Check validity of string
     * @param accStr
     * @return 
     * -1 if is not a DATA AXL measurement
     * 0 if it is a DATA AXL but not complete
     * 1 if it is a DATA AXL complete
     * 
     */
    private int checkValidity(String accStr) {
        if (!accStr.startsWith("D")) {
            return -1;
        } else {
            //extract only the triple of values
            String tmpStr = accStr.substring(10);
            StringTokenizer tokenizer = new StringTokenizer(tmpStr);
            try {
                float alfa = Float.parseFloat(tokenizer.nextToken(","));
                float beta = Float.parseFloat(tokenizer.nextToken(","));
                float value = Float.parseFloat(tokenizer.nextToken());
                return 1;
            } catch (NumberFormatException e) {
                return 0;

            }

        }
    }

    public ArrayList<Acceleration> getNewData() {
        //System.out.println("Communicator getNewData invoked");


        return accMeasures;
    }
}
